package puntaelena.facilitylocation.hillclimbing.solver.agents.coalitionspool;

import puntaelena.facilitylocation.hillclimbing.solver.agents.FacilityCoalition;
import puntaelena.facilitylocation.hillclimbing.solver.services.IHillClimbingAgentRegistry;
import puntaelena.facilitylocation.hillclimbing.solver.services.IFcltLocDataService;
import static puntaelena.facilitylocation.hillclimbing.solver.agents.FcltCityNegotiateComputator.*;
import puntaelena.graphsupport.FacilitiesGraph;

public class CoalitionsPair
	implements Comparable<CoalitionsPair>
{
	private static final int UNDEFINED_ID = -1;

	public final FacilityCoalition coalA;
	public final FacilityCoalition coalB;
	double simMsr;

	private final int id;

	private int version;

	private CoalitionsPair(
		FacilityCoalition coalA,
		FacilityCoalition coalB,
		double simMsr,
		int id
	) {
		this.coalA = coalA;
		this.coalB = coalB;
		this.simMsr = simMsr;
		this.id = id;
		version = computeVersion();
	}

	/* default */ CoalitionsPair(
		FacilityCoalition coalA,
		FacilityCoalition coalB,
		int id,
		IHillClimbingAgentRegistry hcagReg
	) {
		this(coalA, coalB, Double.NaN, id);
		update(hcagReg);
	}

	public static CoalitionsPair infimum(FacilitiesGraph fgraph) {
		return new CoalitionsPair(
			null,
			null,
			-fgraph.getInfEdgeValue(),
			UNDEFINED_ID
		);
	}

	public double getSimMsr() {
		return simMsr;
	}

	/* default */ boolean isUptodate() {
		return version == computeVersion();
	}

	/* default */ boolean isAlive(IFcltLocDataService flServ) {
		return
			coalA != null &&
			coalB != null &&
			coalA.isAlive(flServ) &&
			coalB.isAlive(flServ);
	}

	/* default */ void update(IHillClimbingAgentRegistry hcagReg) {
		simMsr = computeRateSimilarity(coalA, coalB, hcagReg);
		version = computeVersion();
	}

	@Override
	public int compareTo(CoalitionsPair that) {
		return
			this.simMsr < that.simMsr ?
				1 :
				this.simMsr > that.simMsr ? -1 :
					this.id - that.id;
	}

	@Override
	public boolean equals(Object o) {
		if (!(o instanceof CoalitionsPair)) {
			return false;
		}
		CoalitionsPair that = (CoalitionsPair) o;
		return pairsEqual(this, that, false, Double.NaN);
	}

	private int computeVersion() {
		return
			coalA == null || coalB == null ?
				NOT_INIT_VERSION :
					coalA.getNegotiationegVersion() +
					coalB.getNegotiationegVersion();
	}
}
